/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * vim: set ts=8 sts=4 et sw=4 tw=99: * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"vm/TypedArrayObject-inl.h"#include"vm/TypedArrayObject.h"#include"mozilla/Alignment.h"#include"mozilla/Casting.h"#include"mozilla/FloatingPoint.h"#include"mozilla/PodOperations.h"#include<string.h>#ifndef XP_WIN# include <sys/mman.h>#endif#include"jsapi.h"#include"jsarray.h"#include"jscntxt.h"#include"jscpucfg.h"#include"jsnum.h"#include"jsobj.h"#include"jstypes.h"#include"jsutil.h"#ifdef XP_WIN# include "jswin.h"#endif#include"jswrapper.h"#include"builtin/DataViewObject.h"#include"builtin/TypedObjectConstants.h"#include"gc/Barrier.h"#include"gc/Marking.h"#include"jit/InlinableNatives.h"#include"js/Conversions.h"#include"vm/ArrayBufferObject.h"#include"vm/GlobalObject.h"#include"vm/Interpreter.h"#include"vm/PIC.h"#include"vm/SelfHosting.h"#include"vm/SharedMem.h"#include"vm/WrapperObject.h"#include"jsatominlines.h"#include"gc/Nursery-inl.h"#include"gc/StoreBuffer-inl.h"#include"vm/ArrayBufferObject-inl.h"#include"vm/NativeObject-inl.h"#include"vm/Shape-inl.h"usingnamespacejs;usingnamespacejs::gc;usingmozilla::AssertedCast;usingJS::CanonicalizeNaN;usingJS::ToInt32;usingJS::ToUint32;/* * TypedArrayObject * * The non-templated base class for the specific typed implementations. * This class holds all the member variables that are used by * the subclasses. *//* static */intTypedArrayObject::lengthOffset(){returnNativeObject::getFixedSlotOffset(LENGTH_SLOT);}/* static */intTypedArrayObject::dataOffset(){returnNativeObject::getPrivateDataOffset(DATA_SLOT);}voidTypedArrayObject::notifyBufferDetached(JSContext*cx,void*newData){MOZ_ASSERT(!isSharedMemory());setFixedSlot(TypedArrayObject::LENGTH_SLOT,Int32Value(0));setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT,Int32Value(0));// If the object is in the nursery, the buffer will be freed by the next// nursery GC. Free the data slot pointer if the object has no inline data.Nursery&nursery=cx->nursery();if(isTenured()&&!hasBuffer()&&!hasInlineElements()&&!nursery.isInside(elements())){js_free(elements());}setPrivate(newData);}/* static */boolTypedArrayObject::is(HandleValuev){returnv.isObject()&&v.toObject().is<TypedArrayObject>();}/* static */boolTypedArrayObject::ensureHasBuffer(JSContext*cx,Handle<TypedArrayObject*>tarray){if(tarray->hasBuffer())returntrue;Rooted<ArrayBufferObject*>buffer(cx,ArrayBufferObject::create(cx,tarray->byteLength()));if(!buffer)returnfalse;if(!buffer->addView(cx,tarray))returnfalse;// tarray is not shared, because if it were it would have a buffer.memcpy(buffer->dataPointer(),tarray->viewDataUnshared(),tarray->byteLength());// If the object is in the nursery, the buffer will be freed by the next// nursery GC. Free the data slot pointer if the object has no inline data.Nursery&nursery=cx->nursery();if(tarray->isTenured()&&!tarray->hasInlineElements()&&!nursery.isInside(tarray->elements())){js_free(tarray->elements());}tarray->setPrivate(buffer->dataPointer());tarray->setFixedSlot(TypedArrayObject::BUFFER_SLOT,ObjectValue(*buffer));// Notify compiled jit code that the base pointer has moved.MarkObjectStateChange(cx,tarray);returntrue;}#ifdef DEBUGvoidTypedArrayObject::assertZeroLengthArrayData()const{if(length()==0&&!hasBuffer()){uint8_t*end=fixedData(TypedArrayObject::FIXED_DATA_START);MOZ_ASSERT(end[0]==ZeroLengthArrayData);}}#endif/* static */voidTypedArrayObject::trace(JSTracer*trc,JSObject*objArg){// Handle all tracing required when the object has a buffer.ArrayBufferViewObject::trace(trc,objArg);}voidTypedArrayObject::finalize(FreeOp*fop,JSObject*obj){MOZ_ASSERT(!IsInsideNursery(obj));TypedArrayObject*curObj=&obj->as<TypedArrayObject>();// Template objects or discarded objects (which didn't have enough room// for inner elements). Don't have anything to free.if(!curObj->elementsRaw())return;curObj->assertZeroLengthArrayData();// Typed arrays with a buffer object do not need to be free'dif(curObj->hasBuffer())return;// Free the data slot pointer if it does not point into the old JSObject.if(!curObj->hasInlineElements())js_free(curObj->elements());}/* static */voidTypedArrayObject::objectMoved(JSObject*obj,constJSObject*old){TypedArrayObject*newObj=&obj->as<TypedArrayObject>();constTypedArrayObject*oldObj=&old->as<TypedArrayObject>();// Typed arrays with a buffer object do not need an update.if(oldObj->hasBuffer())return;// Update the data slot pointer if it points to the old JSObject.if(oldObj->hasInlineElements())newObj->setInlineElements();}/* static */size_tTypedArrayObject::objectMovedDuringMinorGC(JSTracer*trc,JSObject*obj,constJSObject*old,gc::AllocKindnewAllocKind){TypedArrayObject*newObj=&obj->as<TypedArrayObject>();constTypedArrayObject*oldObj=&old->as<TypedArrayObject>();MOZ_ASSERT(newObj->elementsRaw()==oldObj->elementsRaw());MOZ_ASSERT(obj->isTenured());// Typed arrays with a buffer object do not need an update.if(oldObj->hasBuffer())return0;Nursery&nursery=obj->zone()->group()->nursery();void*buf=oldObj->elements();if(!nursery.isInside(buf)){nursery.removeMallocedBuffer(buf);return0;}// Determine if we can use inline data for the target array. If this is// possible, the nursery will have picked an allocation size that is large// enough.size_tnbytes=0;switch(oldObj->type()){#define OBJECT_MOVED_TYPED_ARRAY(T, N) \ case Scalar::N: \ nbytes = oldObj->length() * sizeof(T); \ break;JS_FOR_EACH_TYPED_ARRAY(OBJECT_MOVED_TYPED_ARRAY)#undef OBJECT_MOVED_TYPED_ARRAYdefault:MOZ_CRASH("Unsupported TypedArray type");}size_theaderSize=dataOffset()+sizeof(HeapSlot);// See AllocKindForLazyBuffer.MOZ_ASSERT_IF(nbytes==0,headerSize+sizeof(uint8_t)<=GetGCKindBytes(newAllocKind));if(headerSize+nbytes<=GetGCKindBytes(newAllocKind)){MOZ_ASSERT(oldObj->hasInlineElements());#ifdef DEBUGif(nbytes==0){uint8_t*output=newObj->fixedData(TypedArrayObject::FIXED_DATA_START);output[0]=ZeroLengthArrayData;}#endifnewObj->setInlineElements();}else{MOZ_ASSERT(!oldObj->hasInlineElements());AutoEnterOOMUnsafeRegionoomUnsafe;nbytes=JS_ROUNDUP(nbytes,sizeof(Value));void*data=newObj->zone()->pod_malloc<uint8_t>(nbytes);if(!data)oomUnsafe.crash("Failed to allocate typed array elements while tenuring.");MOZ_ASSERT(!nursery.isInside(data));newObj->initPrivate(data);}mozilla::PodCopy(newObj->elements(),oldObj->elements(),nbytes);// Set a forwarding pointer for the element buffers in case they were// preserved on the stack by Ion.nursery.maybeSetForwardingPointer(trc,oldObj->elements(),newObj->elements(),/* direct = */nbytes>=sizeof(uintptr_t));returnnewObj->hasInlineElements()?0:nbytes;}boolTypedArrayObject::hasInlineElements()const{returnelements()==this->fixedData(TypedArrayObject::FIXED_DATA_START)&&byteLength()<=TypedArrayObject::INLINE_BUFFER_LIMIT;}voidTypedArrayObject::setInlineElements(){char*dataSlot=reinterpret_cast<char*>(this)+this->dataOffset();*reinterpret_cast<void**>(dataSlot)=this->fixedData(TypedArrayObject::FIXED_DATA_START);}/* Helper clamped uint8_t type */uint32_tJS_FASTCALLjs::ClampDoubleToUint8(constdoublex){// Not < so that NaN coerces to 0if(!(x>=0))return0;if(x>255)return255;doubletoTruncate=x+0.5;uint8_ty=uint8_t(toTruncate);/* * now val is rounded to nearest, ties rounded up. We want * rounded to nearest ties to even, so check whether we had a * tie. */if(y==toTruncate){/* * It was a tie (since adding 0.5 gave us the exact integer * we want). Since we rounded up, we either already have an * even number or we have an odd number but the number we * want is one less. So just unconditionally masking out the * ones bit should do the trick to get us the value we * want. */returny&~1;}returny;}template<typenameElementType>staticinlineJSObject*NewArray(JSContext*cx,uint32_tnelements);namespace{// We allow nullptr for newTarget for all the creation methods, to allow for// JSFriendAPI functions that don't care about subclassingstaticboolGetPrototypeForInstance(JSContext*cx,HandleObjectnewTarget,MutableHandleObjectproto){if(newTarget){if(!GetPrototypeFromConstructor(cx,newTarget,proto))returnfalse;}else{proto.set(nullptr);}returntrue;}enumclassSpeciesConstructorOverride{None,ArrayBuffer};template<typenameNativeType>classTypedArrayObjectTemplate:publicTypedArrayObject{friendclassTypedArrayObject;public:staticconstexprScalar::TypeArrayTypeID(){returnTypeIDOfType<NativeType>::id;}staticboolArrayTypeIsUnsigned(){returnTypeIsUnsigned<NativeType>();}staticboolArrayTypeIsFloatingPoint(){returnTypeIsFloatingPoint<NativeType>();}staticconstsize_tBYTES_PER_ELEMENT=sizeof(NativeType);staticJSObject*createPrototype(JSContext*cx,JSProtoKeykey){Handle<GlobalObject*>global=cx->global();RootedObjecttypedArrayProto(cx,GlobalObject::getOrCreateTypedArrayPrototype(cx,global));if(!typedArrayProto)returnnullptr;constClass*clasp=TypedArrayObject::protoClassForType(ArrayTypeID());returnGlobalObject::createBlankPrototypeInheriting(cx,global,clasp,typedArrayProto);}staticJSObject*createConstructor(JSContext*cx,JSProtoKeykey){Handle<GlobalObject*>global=cx->global();RootedFunctionctorProto(cx,GlobalObject::getOrCreateTypedArrayConstructor(cx,global));if(!ctorProto)returnnullptr;JSFunction*fun=NewFunctionWithProto(cx,class_constructor,3,JSFunction::NATIVE_CTOR,nullptr,ClassName(key,cx),ctorProto,gc::AllocKind::FUNCTION,SingletonObject);if(fun)fun->setJitInfo(&jit::JitInfo_TypedArrayConstructor);returnfun;}staticinlineconstClass*instanceClass(){returnTypedArrayObject::classForType(ArrayTypeID());}staticboolis(HandleValuev){returnv.isObject()&&v.toObject().hasClass(instanceClass());}staticvoidsetIndexValue(TypedArrayObject&tarray,uint32_tindex,doubled){// If the array is an integer array, we only handle up to// 32-bit ints from this point on. if we want to handle// 64-bit ints, we'll need some changes.// Assign based on characteristics of the destination typeif(ArrayTypeIsFloatingPoint()){setIndex(tarray,index,NativeType(d));}elseif(ArrayTypeIsUnsigned()){MOZ_ASSERT(sizeof(NativeType)<=4);uint32_tn=ToUint32(d);setIndex(tarray,index,NativeType(n));}elseif(ArrayTypeID()==Scalar::Uint8Clamped){// The uint8_clamped type has a special rounding converter// for doubles.setIndex(tarray,index,NativeType(d));}else{MOZ_ASSERT(sizeof(NativeType)<=4);int32_tn=ToInt32(d);setIndex(tarray,index,NativeType(n));}}staticTypedArrayObject*makeProtoInstance(JSContext*cx,HandleObjectproto,AllocKindallocKind){MOZ_ASSERT(proto);JSObject*obj=NewObjectWithClassProto(cx,instanceClass(),proto,allocKind);returnobj?&obj->as<TypedArrayObject>():nullptr;}staticTypedArrayObject*makeTypedInstance(JSContext*cx,uint32_tlen,gc::AllocKindallocKind){constClass*clasp=instanceClass();if(len*sizeof(NativeType)>=TypedArrayObject::SINGLETON_BYTE_LENGTH){JSObject*obj=NewBuiltinClassInstance(cx,clasp,allocKind,SingletonObject);if(!obj)returnnullptr;return&obj->as<TypedArrayObject>();}jsbytecode*pc;RootedScriptscript(cx,cx->currentScript(&pc));NewObjectKindnewKind=GenericObject;if(script&&ObjectGroup::useSingletonForAllocationSite(script,pc,clasp))newKind=SingletonObject;RootedObjectobj(cx,NewBuiltinClassInstance(cx,clasp,allocKind,newKind));if(!obj)returnnullptr;if(script&&!ObjectGroup::setAllocationSiteObjectGroup(cx,script,pc,obj,newKind==SingletonObject)){returnnullptr;}return&obj->as<TypedArrayObject>();}staticTypedArrayObject*makeInstance(JSContext*cx,Handle<ArrayBufferObjectMaybeShared*>buffer,uint32_tbyteOffset,uint32_tlen,HandleObjectproto){MOZ_ASSERT_IF(!buffer,byteOffset==0);MOZ_ASSERT_IF(buffer,!buffer->isDetached());MOZ_ASSERT(len<INT32_MAX/sizeof(NativeType));gc::AllocKindallocKind=buffer?GetGCObjectKind(instanceClass()):AllocKindForLazyBuffer(len*sizeof(NativeType));// Subclassing mandates that we hand in the proto every time. Most of// the time, though, that [[Prototype]] will not be interesting. If// it isn't, we can do some more TI optimizations.RootedObjectcheckProto(cx);if(!GetBuiltinPrototype(cx,JSCLASS_CACHED_PROTO_KEY(instanceClass()),&checkProto))returnnullptr;AutoSetNewObjectMetadatametadata(cx);Rooted<TypedArrayObject*>obj(cx);if(proto&&proto!=checkProto)obj=makeProtoInstance(cx,proto,allocKind);elseobj=makeTypedInstance(cx,len,allocKind);if(!obj)returnnullptr;boolisSharedMemory=buffer&&IsSharedArrayBuffer(buffer.get());obj->setFixedSlot(TypedArrayObject::BUFFER_SLOT,ObjectOrNullValue(buffer));// This is invariant. Self-hosting code that sets BUFFER_SLOT// (if it does) must maintain it, should it need to.if(isSharedMemory)obj->setIsSharedMemory();if(buffer){obj->initViewData(buffer->dataPointerEither()+byteOffset);// If the buffer is for an inline typed object, the data pointer// may be in the nursery, so include a barrier to make sure this// object is updated if that typed object moves.autoptr=buffer->dataPointerEither();if(!IsInsideNursery(obj)&&cx->nursery().isInside(ptr)){// Shared buffer data should never be nursery-allocated, so we// need to fail here if isSharedMemory. However, mmap() can// place a SharedArrayRawBuffer up against the bottom end of a// nursery chunk, and a zero-length buffer will erroneously be// perceived as being inside the nursery; sidestep that.if(isSharedMemory){MOZ_ASSERT(buffer->byteLength()==0&&(uintptr_t(ptr.unwrapValue())&gc::ChunkMask)==0);}else{cx->zone()->group()->storeBuffer().putWholeCell(obj);}}}else{void*data=obj->fixedData(FIXED_DATA_START);obj->initPrivate(data);memset(data,0,len*sizeof(NativeType));#ifdef DEBUGif(len==0){uint8_t*elements=static_cast<uint8_t*>(data);elements[0]=ZeroLengthArrayData;}#endif}obj->setFixedSlot(TypedArrayObject::LENGTH_SLOT,Int32Value(len));obj->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT,Int32Value(byteOffset));#ifdef DEBUGif(buffer){uint32_tarrayByteLength=obj->byteLength();uint32_tarrayByteOffset=obj->byteOffset();uint32_tbufferByteLength=buffer->byteLength();// Unwraps are safe: both are for the pointer value.if(IsArrayBuffer(buffer.get())){MOZ_ASSERT_IF(!AsArrayBuffer(buffer.get()).isDetached(),buffer->dataPointerEither().unwrap(/*safe*/)<=obj->viewDataEither().unwrap(/*safe*/));}MOZ_ASSERT(bufferByteLength-arrayByteOffset>=arrayByteLength);MOZ_ASSERT(arrayByteOffset<=bufferByteLength);}// Verify that the private slot is at the expected placeMOZ_ASSERT(obj->numFixedSlots()==TypedArrayObject::DATA_SLOT);#endif// ArrayBufferObjects track their views to support detaching.if(buffer&&buffer->is<ArrayBufferObject>()){if(!buffer->as<ArrayBufferObject>().addView(cx,obj))returnnullptr;}returnobj;}staticTypedArrayObject*makeTemplateObject(JSContext*cx,int32_tlen){MOZ_ASSERT(len>=0);size_tnbytes;MOZ_ALWAYS_TRUE(CalculateAllocSize<NativeType>(len,&nbytes));MOZ_ASSERT(nbytes<TypedArrayObject::SINGLETON_BYTE_LENGTH);NewObjectKindnewKind=TenuredObject;boolfitsInline=nbytes<=INLINE_BUFFER_LIMIT;constClass*clasp=instanceClass();gc::AllocKindallocKind=!fitsInline?GetGCObjectKind(clasp):AllocKindForLazyBuffer(nbytes);MOZ_ASSERT(CanBeFinalizedInBackground(allocKind,clasp));allocKind=GetBackgroundAllocKind(allocKind);AutoSetNewObjectMetadatametadata(cx);jsbytecode*pc;RootedScriptscript(cx,cx->currentScript(&pc));if(script&&ObjectGroup::useSingletonForAllocationSite(script,pc,clasp))newKind=SingletonObject;JSObject*tmp=NewBuiltinClassInstance(cx,clasp,allocKind,newKind);if(!tmp)returnnullptr;Rooted<TypedArrayObject*>tarray(cx,&tmp->as<TypedArrayObject>());initTypedArraySlots(cx,tarray,len);// Template objects do not need memory for its elements, since there// won't be any elements to store. Therefore, we set the pointer to// nullptr and avoid allocating memory that will never be used.tarray->initPrivate(nullptr);if(script&&!ObjectGroup::setAllocationSiteObjectGroup(cx,script,pc,tarray,newKind==SingletonObject)){returnnullptr;}returntarray;}staticvoidinitTypedArraySlots(JSContext*cx,TypedArrayObject*tarray,int32_tlen){MOZ_ASSERT(len>=0);tarray->setFixedSlot(TypedArrayObject::BUFFER_SLOT,NullValue());tarray->setFixedSlot(TypedArrayObject::LENGTH_SLOT,Int32Value(AssertedCast<int32_t>(len)));tarray->setFixedSlot(TypedArrayObject::BYTEOFFSET_SLOT,Int32Value(0));// Verify that the private slot is at the expected place.MOZ_ASSERT(tarray->numFixedSlots()==TypedArrayObject::DATA_SLOT);#ifdef DEBUGif(len==0){uint8_t*output=tarray->fixedData(TypedArrayObject::FIXED_DATA_START);output[0]=TypedArrayObject::ZeroLengthArrayData;}#endif}staticvoidinitTypedArrayData(JSContext*cx,TypedArrayObject*tarray,int32_tlen,void*buf,AllocKindallocKind){if(buf){#ifdef DEBUGNursery&nursery=cx->nursery();MOZ_ASSERT_IF(!nursery.isInside(buf)&&!tarray->hasInlineElements(),tarray->isTenured());#endiftarray->initPrivate(buf);}else{size_tnbytes=len*sizeof(NativeType);#ifdef DEBUGsize_tdataOffset=TypedArrayObject::dataOffset();size_toffset=dataOffset+sizeof(HeapSlot);MOZ_ASSERT(offset+nbytes<=GetGCKindBytes(allocKind));#endifvoid*data=tarray->fixedData(FIXED_DATA_START);tarray->initPrivate(data);memset(data,0,nbytes);}}staticTypedArrayObject*makeTypedArrayWithTemplate(JSContext*cx,TypedArrayObject*templateObj,int32_tlen){if(len<0||uint32_t(len)>=INT32_MAX/sizeof(NativeType)){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_BAD_ARRAY_LENGTH);returnnullptr;}size_tnbytes;MOZ_ALWAYS_TRUE(js::CalculateAllocSize<NativeType>(len,&nbytes));boolfitsInline=nbytes<=INLINE_BUFFER_LIMIT;AutoSetNewObjectMetadatametadata(cx);constClass*clasp=templateObj->group()->clasp();gc::AllocKindallocKind=!fitsInline?GetGCObjectKind(clasp):AllocKindForLazyBuffer(nbytes);MOZ_ASSERT(CanBeFinalizedInBackground(allocKind,clasp));allocKind=GetBackgroundAllocKind(allocKind);RootedObjectGroupgroup(cx,templateObj->group());NewObjectKindnewKind=TenuredObject;ScopedJSFreePtr<void>buf;if(!fitsInline&&len>0){buf=cx->zone()->pod_malloc<uint8_t>(nbytes);if(!buf){ReportOutOfMemory(cx);returnnullptr;}memset(buf,0,nbytes);}RootedObjecttmp(cx,NewObjectWithGroup<TypedArrayObject>(cx,group,allocKind,newKind));if(!tmp)returnnullptr;TypedArrayObject*obj=&tmp->as<TypedArrayObject>();initTypedArraySlots(cx,obj,len);initTypedArrayData(cx,obj,len,buf.forget(),allocKind);returnobj;}// ES2018 draft rev 8340bf9a8427ea81bb0d1459471afbcc91d18add// 22.2.4.1 TypedArray ( )// 22.2.4.2 TypedArray ( length )// 22.2.4.3 TypedArray ( typedArray )// 22.2.4.4 TypedArray ( object )// 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )staticboolclass_constructor(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);// Step 1 (22.2.4.1) or 2 (22.2.4.2-5).if(!ThrowIfNotConstructing(cx,args,"typed array"))returnfalse;JSObject*obj=create(cx,args);if(!obj)returnfalse;args.rval().setObject(*obj);returntrue;}private:staticJSObject*create(JSContext*cx,constCallArgs&args){MOZ_ASSERT(args.isConstructing());RootedObjectnewTarget(cx,&args.newTarget().toObject());// 22.2.4.1 TypedArray ( )// 22.2.4.2 TypedArray ( length )if(args.length()==0||!args[0].isObject()){// 22.2.4.2, step 3.uint64_tlen;if(!ToIndex(cx,args.get(0),JSMSG_BAD_ARRAY_LENGTH,&len))returnnullptr;returnfromLength(cx,len,newTarget);}RootedObjectdataObj(cx,&args[0].toObject());// 22.2.4.3 TypedArray ( typedArray )// 22.2.4.4 TypedArray ( object )if(!UncheckedUnwrap(dataObj)->is<ArrayBufferObjectMaybeShared>())returnfromArray(cx,dataObj,newTarget);// 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )// Step 4.// 22.2.4.2.1 AllocateTypedArray, step 1.RootedObjectproto(cx);if(!GetPrototypeFromConstructor(cx,newTarget,&proto))returnnullptr;uint64_tbyteOffset=0;if(args.hasDefined(1)){// Step 6.if(!ToIndex(cx,args[1],&byteOffset))returnnullptr;// Step 7.if(byteOffset%sizeof(NativeType)!=0){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);returnnullptr;}}uint64_tlength=UINT64_MAX;if(args.hasDefined(2)){// Step 8.a.if(!ToIndex(cx,args[2],&length))returnnullptr;}// Steps 9-17.if(dataObj->is<ArrayBufferObjectMaybeShared>()){HandleArrayBufferObjectMaybeSharedbuffer=dataObj.as<ArrayBufferObjectMaybeShared>();returnfromBufferSameCompartment(cx,buffer,byteOffset,length,proto);}returnfromBufferWrapped(cx,dataObj,byteOffset,length,proto);}// ES2018 draft rev 8340bf9a8427ea81bb0d1459471afbcc91d18add// 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )// Steps 9-12.staticboolcomputeAndCheckLength(JSContext*cx,HandleArrayBufferObjectMaybeSharedbufferMaybeUnwrapped,uint64_tbyteOffset,uint64_tlengthIndex,uint32_t*length){MOZ_ASSERT(byteOffset%sizeof(NativeType)==0);MOZ_ASSERT(byteOffset<uint64_t(DOUBLE_INTEGRAL_PRECISION_LIMIT));MOZ_ASSERT_IF(lengthIndex!=UINT64_MAX,lengthIndex<uint64_t(DOUBLE_INTEGRAL_PRECISION_LIMIT));// Step 9.if(bufferMaybeUnwrapped->isDetached()){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_DETACHED);returnfalse;}// Step 10.uint32_tbufferByteLength=bufferMaybeUnwrapped->byteLength();uint32_tlen;if(lengthIndex==UINT64_MAX){// Steps 11.a, 11.c.if(bufferByteLength%sizeof(NativeType)!=0||byteOffset>bufferByteLength){// The given byte array doesn't map exactly to// |sizeof(NativeType) * N| or |byteOffset| is invalid.JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);returnfalse;}// Step 11.b.uint32_tnewByteLength=bufferByteLength-uint32_t(byteOffset);len=newByteLength/sizeof(NativeType);}else{// Step 12.a.uint64_tnewByteLength=lengthIndex*sizeof(NativeType);// Step 12.b.if(byteOffset+newByteLength>bufferByteLength){// |byteOffset + newByteLength| is too big for the arraybufferJS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);returnfalse;}len=uint32_t(lengthIndex);}// ArrayBuffer is too large for TypedArrays:// Standalone ArrayBuffers can hold up to INT32_MAX bytes, whereas// buffers in TypedArrays must have less than or equal to// |INT32_MAX - sizeof(NativeType) - INT32_MAX % sizeof(NativeType)|// bytes.if(len>=INT32_MAX/sizeof(NativeType)){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);returnfalse;}MOZ_ASSERT(byteOffset<=UINT32_MAX);*length=len;returntrue;}// ES2018 draft rev 8340bf9a8427ea81bb0d1459471afbcc91d18add// 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] )// Steps 9-17.staticJSObject*fromBufferSameCompartment(JSContext*cx,HandleArrayBufferObjectMaybeSharedbuffer,uint64_tbyteOffset,uint64_tlengthIndex,HandleObjectproto){// Steps 9-12.uint32_tlength;if(!computeAndCheckLength(cx,buffer,byteOffset,lengthIndex,&length))returnnullptr;// Steps 13-17.returnmakeInstance(cx,buffer,uint32_t(byteOffset),length,proto);}// Create a TypedArray object in another compartment.//// ES6 supports creating a TypedArray in global A (using global A's// TypedArray constructor) backed by an ArrayBuffer created in global B.//// Our TypedArrayObject implementation doesn't support a TypedArray in// compartment A backed by an ArrayBuffer in compartment B. So in this// case, we create the TypedArray in B (!) and return a cross-compartment// wrapper.//// Extra twist: the spec says the new TypedArray's [[Prototype]] must be// A's TypedArray.prototype. So even though we're creating the TypedArray// in B, its [[Prototype]] must be (a cross-compartment wrapper for) the// TypedArray.prototype in A.staticJSObject*fromBufferWrapped(JSContext*cx,HandleObjectbufobj,uint64_tbyteOffset,uint64_tlengthIndex,HandleObjectproto){JSObject*unwrapped=CheckedUnwrap(bufobj);if(!unwrapped){ReportAccessDenied(cx);returnnullptr;}if(!unwrapped->is<ArrayBufferObjectMaybeShared>()){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_BAD_ARGS);returnnullptr;}RootedArrayBufferObjectMaybeSharedunwrappedBuffer(cx);unwrappedBuffer=&unwrapped->as<ArrayBufferObjectMaybeShared>();uint32_tlength;if(!computeAndCheckLength(cx,unwrappedBuffer,byteOffset,lengthIndex,&length))returnnullptr;// Make sure to get the [[Prototype]] for the created typed array from// this compartment.RootedObjectprotoRoot(cx,proto);if(!protoRoot){if(!GetBuiltinPrototype(cx,JSCLASS_CACHED_PROTO_KEY(instanceClass()),&protoRoot))returnnullptr;}RootedObjecttypedArray(cx);{JSAutoCompartmentac(cx,unwrappedBuffer);RootedObjectwrappedProto(cx,protoRoot);if(!cx->compartment()->wrap(cx,&wrappedProto))returnnullptr;typedArray=makeInstance(cx,unwrappedBuffer,uint32_t(byteOffset),length,wrappedProto);if(!typedArray)returnnullptr;}if(!cx->compartment()->wrap(cx,&typedArray))returnnullptr;returntypedArray;}public:staticJSObject*fromBuffer(JSContext*cx,HandleObjectbufobj,uint32_tbyteOffset,int32_tlengthInt){if(byteOffset%sizeof(NativeType)!=0){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_CONSTRUCT_BOUNDS);returnnullptr;// invalid byteOffset}uint64_tlengthIndex=lengthInt>=0?uint64_t(lengthInt):UINT64_MAX;if(bufobj->is<ArrayBufferObjectMaybeShared>()){HandleArrayBufferObjectMaybeSharedbuffer=bufobj.as<ArrayBufferObjectMaybeShared>();returnfromBufferSameCompartment(cx,buffer,byteOffset,lengthIndex,nullptr);}returnfromBufferWrapped(cx,bufobj,byteOffset,lengthIndex,nullptr);}staticboolmaybeCreateArrayBuffer(JSContext*cx,uint32_tcount,uint32_tunit,HandleObjectnonDefaultProto,MutableHandle<ArrayBufferObject*>buffer){if(count>=INT32_MAX/unit){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_BAD_ARRAY_LENGTH);returnfalse;}uint32_tbyteLength=count*unit;MOZ_ASSERT(byteLength<INT32_MAX);static_assert(INLINE_BUFFER_LIMIT%sizeof(NativeType)==0,"ArrayBuffer inline storage shouldn't waste any space");if(!nonDefaultProto&&byteLength<=INLINE_BUFFER_LIMIT){// The array's data can be inline, and the buffer created lazily.returntrue;}ArrayBufferObject*buf=ArrayBufferObject::create(cx,byteLength,nonDefaultProto);if(!buf)returnfalse;buffer.set(buf);returntrue;}// 22.2.4.1 TypedArray ( )// 22.2.4.2 TypedArray ( length )staticJSObject*fromLength(JSContext*cx,uint64_tnelements,HandleObjectnewTarget=nullptr){// 22.2.4.1, step 1 and 22.2.4.2, steps 1-3 (performed in caller).// 22.2.4.1, step 2 and 22.2.4.2, step 4 (implicit).// 22.2.4.1, step 3 and 22.2.4.2, step 5.// 22.2.4.2.1 AllocateTypedArray, step 1.RootedObjectproto(cx);if(!GetPrototypeForInstance(cx,newTarget,&proto))returnnullptr;if(nelements>UINT32_MAX){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_BAD_ARRAY_LENGTH);returnnullptr;}Rooted<ArrayBufferObject*>buffer(cx);if(!maybeCreateArrayBuffer(cx,uint32_t(nelements),BYTES_PER_ELEMENT,nullptr,&buffer))returnnullptr;returnmakeInstance(cx,buffer,0,uint32_t(nelements),proto);}staticboolAllocateArrayBuffer(JSContext*cx,HandleValuector,uint32_tcount,uint32_tunit,MutableHandle<ArrayBufferObject*>buffer);staticboolCloneArrayBufferNoCopy(JSContext*cx,Handle<ArrayBufferObjectMaybeShared*>srcBuffer,boolisWrapped,uint32_tsrcByteOffset,uint32_tsrcLength,SpeciesConstructorOverrideoverride,MutableHandle<ArrayBufferObject*>buffer);staticJSObject*fromArray(JSContext*cx,HandleObjectother,HandleObjectnewTarget=nullptr);staticJSObject*fromTypedArray(JSContext*cx,HandleObjectother,boolisWrapped,HandleObjectnewTarget);staticJSObject*fromObject(JSContext*cx,HandleObjectother,HandleObjectnewTarget);staticconstNativeTypegetIndex(JSObject*obj,uint32_tindex){TypedArrayObject&tarray=obj->as<TypedArrayObject>();MOZ_ASSERT(index<tarray.length());returnjit::AtomicOperations::loadSafeWhenRacy(tarray.viewDataEither().cast<NativeType*>()+index);}staticvoidsetIndex(TypedArrayObject&tarray,uint32_tindex,NativeTypeval){MOZ_ASSERT(index<tarray.length());jit::AtomicOperations::storeSafeWhenRacy(tarray.viewDataEither().cast<NativeType*>()+index,val);}staticValuegetIndexValue(JSObject*tarray,uint32_tindex);};#define CREATE_TYPE_FOR_TYPED_ARRAY(T, N) \ typedef TypedArrayObjectTemplate<T> N##Array;JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPE_FOR_TYPED_ARRAY)#undef CREATE_TYPE_FOR_TYPED_ARRAY}/* anonymous namespace */TypedArrayObject*js::TypedArrayCreateWithTemplate(JSContext*cx,HandleObjecttemplateObj,int32_tlen){MOZ_ASSERT(templateObj->is<TypedArrayObject>());TypedArrayObject*tobj=&templateObj->as<TypedArrayObject>();switch(tobj->type()){#define CREATE_TYPED_ARRAY(T, N) \ case Scalar::N: \ return TypedArrayObjectTemplate<T>::makeTypedArrayWithTemplate(cx, tobj, len);JS_FOR_EACH_TYPED_ARRAY(CREATE_TYPED_ARRAY)#undef CREATE_TYPED_ARRAYdefault:MOZ_CRASH("Unsupported TypedArray type");}}// ES 2016 draft Mar 25, 2016 24.1.1.1.// byteLength = count * unittemplate<typenameT>/* static */boolTypedArrayObjectTemplate<T>::AllocateArrayBuffer(JSContext*cx,HandleValuector,uint32_tcount,uint32_tunit,MutableHandle<ArrayBufferObject*>buffer){// ES 2016 draft Mar 25, 2016 24.1.1.1 step 1 (partially).// ES 2016 draft Mar 25, 2016 9.1.14 steps 1-2.MOZ_ASSERT(ctor.isObject());RootedObjectproto(cx);RootedObjectctorObj(cx,&ctor.toObject());if(!GetPrototypeFromConstructor(cx,ctorObj,&proto))returnfalse;JSObject*arrayBufferProto=GlobalObject::getOrCreateArrayBufferPrototype(cx,cx->global());if(!arrayBufferProto)returnfalse;if(proto==arrayBufferProto)proto=nullptr;// ES 2016 draft Mar 25, 2016 24.1.1.1 steps 1 (remaining part), 2-6.if(!maybeCreateArrayBuffer(cx,count,unit,proto,buffer))returnfalse;returntrue;}staticboolIsArrayBufferConstructor(constValue&v){returnv.isObject()&&v.toObject().is<JSFunction>()&&v.toObject().as<JSFunction>().isNative()&&v.toObject().as<JSFunction>().native()==ArrayBufferObject::class_constructor;}staticboolIsArrayBufferSpecies(JSContext*cx,HandleObjectorigBuffer){RootedValuector(cx);if(!GetPropertyPure(cx,origBuffer,NameToId(cx->names().constructor),ctor.address()))returnfalse;if(!IsArrayBufferConstructor(ctor))returnfalse;RootedObjectctorObj(cx,&ctor.toObject());RootedIdspeciesId(cx,SYMBOL_TO_JSID(cx->wellKnownSymbols().species));JSFunction*getter;if(!GetGetterPure(cx,ctorObj,speciesId,&getter))returnfalse;if(!getter)returnfalse;returnIsSelfHostedFunctionWithName(getter,cx->names().ArrayBufferSpecies);}staticboolGetSpeciesConstructor(JSContext*cx,HandleObjectobj,boolisWrapped,SpeciesConstructorOverrideoverride,MutableHandleValuector){if(!GlobalObject::ensureConstructor(cx,cx->global(),JSProto_ArrayBuffer))returnfalse;RootedValuedefaultCtor(cx,cx->global()->getConstructor(JSProto_ArrayBuffer));// Use the current global's ArrayBuffer if the override is set.if(override==SpeciesConstructorOverride::ArrayBuffer){ctor.set(defaultCtor);returntrue;}if(!isWrapped){// As an optimization, avoid calling into self-hosted code if |obj|'s// constructor is the built-in ArrayBuffer and the constructor's// species property is the original ArrayBuffer[@@species] function.if(IsArrayBufferSpecies(cx,obj))ctor.set(defaultCtor);elseif(!SpeciesConstructor(cx,obj,defaultCtor,ctor))returnfalse;returntrue;}RootedObjectwrappedObj(cx,obj);if(!cx->compartment()->wrap(cx,&wrappedObj))returnfalse;if(!SpeciesConstructor(cx,wrappedObj,defaultCtor,ctor))returnfalse;returntrue;}// ES 2017 draft rev 8633ffd9394b203b8876bb23cb79aff13eb07310 24.1.1.4.template<typenameT>/* static */boolTypedArrayObjectTemplate<T>::CloneArrayBufferNoCopy(JSContext*cx,Handle<ArrayBufferObjectMaybeShared*>srcBuffer,boolisWrapped,uint32_tsrcByteOffset,uint32_tsrcLength,SpeciesConstructorOverrideoverride,MutableHandle<ArrayBufferObject*>buffer){// Step 1 (skipped).// Step 2.a.RootedValuecloneCtor(cx);if(!GetSpeciesConstructor(cx,srcBuffer,isWrapped,override,&cloneCtor))returnfalse;// Step 2.b.if(srcBuffer->isDetached()){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_DETACHED);returnfalse;}// Steps 3-4 (skipped).// Steps 5.if(!AllocateArrayBuffer(cx,cloneCtor,srcLength,1,buffer))returnfalse;// Step 6.if(srcBuffer->isDetached()){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_DETACHED);returnfalse;}// Steps 7-8 (done in caller).// Step 9.returntrue;}template<typenameT>/* static */JSObject*TypedArrayObjectTemplate<T>::fromArray(JSContext*cx,HandleObjectother,HandleObjectnewTarget/* = nullptr */){// Allow nullptr newTarget for FriendAPI methods, which don't care about// subclassing.if(other->is<TypedArrayObject>())returnfromTypedArray(cx,other,/* wrapped= */false,newTarget);if(other->is<WrapperObject>()&&UncheckedUnwrap(other)->is<TypedArrayObject>())returnfromTypedArray(cx,other,/* wrapped= */true,newTarget);returnfromObject(cx,other,newTarget);}// ES2017 draft rev 6390c2f1b34b309895d31d8c0512eac8660a0210// 22.2.4.3 TypedArray ( typedArray )template<typenameT>/* static */JSObject*TypedArrayObjectTemplate<T>::fromTypedArray(JSContext*cx,HandleObjectother,boolisWrapped,HandleObjectnewTarget){// Step 1.MOZ_ASSERT_IF(!isWrapped,other->is<TypedArrayObject>());MOZ_ASSERT_IF(isWrapped,other->is<WrapperObject>()&&UncheckedUnwrap(other)->is<TypedArrayObject>());// Step 2 (done in caller).// Step 4 (partially).RootedObjectproto(cx);if(!GetPrototypeForInstance(cx,newTarget,&proto))returnnullptr;// Step 5.Rooted<TypedArrayObject*>srcArray(cx);if(!isWrapped){srcArray=&other->as<TypedArrayObject>();if(!TypedArrayObject::ensureHasBuffer(cx,srcArray))returnnullptr;}else{RootedObjectunwrapped(cx,CheckedUnwrap(other));if(!unwrapped){ReportAccessDenied(cx);returnnullptr;}JSAutoCompartmentac(cx,unwrapped);srcArray=&unwrapped->as<TypedArrayObject>();if(!TypedArrayObject::ensureHasBuffer(cx,srcArray))returnnullptr;}// Step 6.Rooted<ArrayBufferObjectMaybeShared*>srcData(cx,srcArray->bufferEither());// Step 7.if(srcData->isDetached()){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_DETACHED);returnnullptr;}// Step 9.uint32_telementLength=srcArray->length();// Steps 10-11.Scalar::TypesrcType=srcArray->type();// Step 12 (skipped).// Step 13.uint32_tsrcByteOffset=srcArray->byteOffset();// Steps 16-17.boolisShared=srcArray->isSharedMemory();SpeciesConstructorOverrideoverride=isShared?SpeciesConstructorOverride::ArrayBuffer:SpeciesConstructorOverride::None;// Steps 8, 16-17.Rooted<ArrayBufferObject*>buffer(cx);if(ArrayTypeID()==srcType){// Step 16.a.uint32_tsrcLength=srcArray->byteLength();// Steps 16.b-c.if(!CloneArrayBufferNoCopy(cx,srcData,isWrapped,srcByteOffset,srcLength,override,&buffer)){returnnullptr;}}else{// Steps 17.a-b.RootedValuebufferCtor(cx);if(!GetSpeciesConstructor(cx,srcData,isWrapped,override,&bufferCtor))returnnullptr;// Steps 14-15, 17.c.if(!AllocateArrayBuffer(cx,bufferCtor,elementLength,BYTES_PER_ELEMENT,&buffer))returnnullptr;// Step 17.d.if(srcArray->hasDetachedBuffer()){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_DETACHED);returnnullptr;}}// Steps 3-4 (remaining part), 18-21.Rooted<TypedArrayObject*>obj(cx,makeInstance(cx,buffer,0,elementLength,proto));if(!obj)returnnullptr;// Steps 17.e-h or 24.1.1.4 step 8.MOZ_ASSERT(!obj->isSharedMemory());if(isShared){if(!ElementSpecific<T,SharedOps>::setFromTypedArray(cx,obj,srcArray,0))returnnullptr;}else{if(!ElementSpecific<T,UnsharedOps>::setFromTypedArray(cx,obj,srcArray,0))returnnullptr;}// Step 22.returnobj;}staticMOZ_ALWAYS_INLINEboolIsOptimizableInit(JSContext*cx,HandleObjectiterable,bool*optimized){MOZ_ASSERT(!*optimized);if(!IsPackedArray(iterable))returntrue;ForOfPIC::Chain*stubChain=ForOfPIC::getOrCreate(cx);if(!stubChain)returnfalse;returnstubChain->tryOptimizeArray(cx,iterable.as<ArrayObject>(),optimized);}// ES2017 draft rev 6859bb9ccaea9c6ede81d71e5320e3833b92cb3e// 22.2.4.4 TypedArray ( object )template<typenameT>/* static */JSObject*TypedArrayObjectTemplate<T>::fromObject(JSContext*cx,HandleObjectother,HandleObjectnewTarget){// Steps 1-2 (Already performed in caller).// Steps 3-4 (Allocation deferred until later).RootedObjectproto(cx);if(!GetPrototypeForInstance(cx,newTarget,&proto))returnnullptr;booloptimized=false;if(!IsOptimizableInit(cx,other,&optimized))returnnullptr;// Fast path when iterable is a packed array using the default iterator.if(optimized){// Step 6.a (We don't need to call IterableToList for the fast path).RootedArrayObjectarray(cx,&other->as<ArrayObject>());// Step 6.b.uint32_tlen=array->getDenseInitializedLength();// Step 6.c.Rooted<ArrayBufferObject*>buffer(cx);if(!maybeCreateArrayBuffer(cx,len,BYTES_PER_ELEMENT,nullptr,&buffer))returnnullptr;Rooted<TypedArrayObject*>obj(cx,makeInstance(cx,buffer,0,len,proto));if(!obj)returnnullptr;// Steps 6.d-e.MOZ_ASSERT(!obj->isSharedMemory());if(!ElementSpecific<T,UnsharedOps>::initFromIterablePackedArray(cx,obj,array))returnnullptr;// Step 6.f (The assertion isn't applicable for the fast path).// Step 6.g.returnobj;}// Step 5.RootedValuecallee(cx);RootedIditeratorId(cx,SYMBOL_TO_JSID(cx->wellKnownSymbols().iterator));if(!GetProperty(cx,other,other,iteratorId,&callee))returnnullptr;// Steps 6-8.RootedObjectarrayLike(cx);if(!callee.isNullOrUndefined()){// Throw if other[Symbol.iterator] isn't callable.if(!callee.isObject()||!callee.toObject().isCallable()){RootedValueotherVal(cx,ObjectValue(*other));UniqueCharsbytes=DecompileValueGenerator(cx,JSDVG_SEARCH_STACK,otherVal,nullptr);if(!bytes)returnnullptr;JS_ReportErrorNumberLatin1(cx,GetErrorMessage,nullptr,JSMSG_NOT_ITERABLE,bytes.get());returnnullptr;}FixedInvokeArgs<2>args2(cx);args2[0].setObject(*other);args2[1].set(callee);// Step 6.a.RootedValuerval(cx);if(!CallSelfHostedFunction(cx,cx->names().IterableToList,UndefinedHandleValue,args2,&rval)){returnnullptr;}// Steps 6.b-g (Implemented in steps 9-13 below).arrayLike=&rval.toObject();}else{// Step 7 is an assertion: object is not an Iterator. Testing this is// literally the very last thing we did, so we don't assert here.// Step 8.arrayLike=other;}// Step 9.uint32_tlen;if(!GetLengthProperty(cx,arrayLike,&len))returnnullptr;// Step 10.Rooted<ArrayBufferObject*>buffer(cx);if(!maybeCreateArrayBuffer(cx,len,BYTES_PER_ELEMENT,nullptr,&buffer))returnnullptr;Rooted<TypedArrayObject*>obj(cx,makeInstance(cx,buffer,0,len,proto));if(!obj)returnnullptr;// Steps 11-12.MOZ_ASSERT(!obj->isSharedMemory());if(!ElementSpecific<T,UnsharedOps>::setFromNonTypedArray(cx,obj,arrayLike,len))returnnullptr;// Step 13.returnobj;}boolTypedArrayConstructor(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_CALL_OR_CONSTRUCT,args.isConstructing()?"construct":"call");returnfalse;}/* static */boolTypedArrayObject::GetTemplateObjectForNative(JSContext*cx,Nativenative,uint32_tlen,MutableHandleObjectres){#define CHECK_TYPED_ARRAY_CONSTRUCTOR(T, N) \ if (native == &TypedArrayObjectTemplate<T>::class_constructor) { \ size_t nbytes; \ if (!js::CalculateAllocSize<T>(len, &nbytes)) \ return true; \ \ if (nbytes < TypedArrayObject::SINGLETON_BYTE_LENGTH) { \ res.set(TypedArrayObjectTemplate<T>::makeTemplateObject(cx, len)); \ return !!res; \ } \ }JS_FOR_EACH_TYPED_ARRAY(CHECK_TYPED_ARRAY_CONSTRUCTOR)#undef CHECK_TYPED_ARRAY_CONSTRUCTORreturntrue;}/* * These next 3 functions are brought to you by the buggy GCC we use to build * B2G ICS. Older GCC versions have a bug in which they fail to compile * reinterpret_casts of templated functions with the message: "insufficient * contextual information to determine type". JS_PSG needs to * reinterpret_cast<JSGetterOp>, so this causes problems for us here. * * We could restructure all this code to make this nicer, but since ICS isn't * going to be around forever (and since this bug is fixed with the newer GCC * versions we use on JB and KK), the workaround here is designed for ease of * removal. When you stop seeing ICS Emulator builds on TBPL, remove these 3 * JSNatives and insert the templated callee directly into the JS_PSG below. */staticboolTypedArray_lengthGetter(JSContext*cx,unsignedargc,Value*vp){returnTypedArrayObject::Getter<TypedArrayObject::lengthValue>(cx,argc,vp);}staticboolTypedArray_byteLengthGetter(JSContext*cx,unsignedargc,Value*vp){returnTypedArrayObject::Getter<TypedArrayObject::byteLengthValue>(cx,argc,vp);}staticboolTypedArray_byteOffsetGetter(JSContext*cx,unsignedargc,Value*vp){returnTypedArrayObject::Getter<TypedArrayObject::byteOffsetValue>(cx,argc,vp);}boolBufferGetterImpl(JSContext*cx,constCallArgs&args){MOZ_ASSERT(TypedArrayObject::is(args.thisv()));Rooted<TypedArrayObject*>tarray(cx,&args.thisv().toObject().as<TypedArrayObject>());if(!TypedArrayObject::ensureHasBuffer(cx,tarray))returnfalse;args.rval().set(TypedArrayObject::bufferValue(tarray));returntrue;}/*static*/booljs::TypedArray_bufferGetter(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);returnCallNonGenericMethod<TypedArrayObject::is,BufferGetterImpl>(cx,args);}/* static */constJSPropertySpecTypedArrayObject::protoAccessors[]={JS_PSG("length",TypedArray_lengthGetter,0),JS_PSG("buffer",TypedArray_bufferGetter,0),JS_PSG("byteLength",TypedArray_byteLengthGetter,0),JS_PSG("byteOffset",TypedArray_byteOffsetGetter,0),JS_SELF_HOSTED_SYM_GET(toStringTag,"TypedArrayToStringTag",0),JS_PS_END};template<typenameT>staticinlineboolSetFromTypedArray(JSContext*cx,Handle<TypedArrayObject*>target,Handle<TypedArrayObject*>source,uint32_toffset){// WARNING: |source| may be an unwrapped typed array from a different// compartment. Proceed with caution!if(target->isSharedMemory()||source->isSharedMemory())returnElementSpecific<T,SharedOps>::setFromTypedArray(cx,target,source,offset);returnElementSpecific<T,UnsharedOps>::setFromTypedArray(cx,target,source,offset);}template<typenameT>staticinlineboolSetFromNonTypedArray(JSContext*cx,Handle<TypedArrayObject*>target,HandleObjectsource,uint32_tlen,uint32_toffset){MOZ_ASSERT(!source->is<TypedArrayObject>(),"use SetFromTypedArray");if(target->isSharedMemory())returnElementSpecific<T,SharedOps>::setFromNonTypedArray(cx,target,source,len,offset);returnElementSpecific<T,UnsharedOps>::setFromNonTypedArray(cx,target,source,len,offset);}// ES2017 draft rev c57ef95c45a371f9c9485bb1c3881dbdc04524a2// 22.2.3.23 %TypedArray%.prototype.set ( overloaded [ , offset ] )// 22.2.3.23.1 %TypedArray%.prototype.set ( array [ , offset ] )// 22.2.3.23.2 %TypedArray%.prototype.set( typedArray [ , offset ] )/* static */boolTypedArrayObject::set_impl(JSContext*cx,constCallArgs&args){MOZ_ASSERT(TypedArrayObject::is(args.thisv()));// Steps 1-5 (Validation performed as part of CallNonGenericMethod).Rooted<TypedArrayObject*>target(cx,&args.thisv().toObject().as<TypedArrayObject>());// Steps 6-7.doubletargetOffset=0;if(args.length()>1){// Step 6.if(!ToInteger(cx,args[1],&targetOffset))returnfalse;// Step 7.if(targetOffset<0){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_BAD_INDEX);returnfalse;}}// Steps 8-9.if(target->hasDetachedBuffer()){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_DETACHED);returnfalse;}// 22.2.3.23.1, step 15. (22.2.3.23.2 only applies if args[0] is a typed// array, so it doesn't make a difference there to apply ToObject here.)RootedObjectsrc(cx,ToObject(cx,args.get(0)));if(!src)returnfalse;Rooted<TypedArrayObject*>srcTypedArray(cx);{JSObject*obj=CheckedUnwrap(src);if(!obj){ReportAccessDenied(cx);returnfalse;}if(obj->is<TypedArrayObject>())srcTypedArray=&obj->as<TypedArrayObject>();}if(srcTypedArray){// Remaining steps of 22.2.3.23.2.// WARNING: |srcTypedArray| may be an unwrapped typed array from a// different compartment. Proceed with caution!// Steps 11-12.if(srcTypedArray->hasDetachedBuffer()){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_DETACHED);returnfalse;}// Step 10 (Reordered).uint32_ttargetLength=target->length();// Step 22 (Split into two checks to provide better error messages).if(targetOffset>targetLength){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_BAD_INDEX);returnfalse;}// Step 22 (Cont'd).uint32_toffset=uint32_t(targetOffset);if(srcTypedArray->length()>targetLength-offset){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_BAD_ARRAY_LENGTH);returnfalse;}// Steps 13-21, 23-28.switch(target->type()){#define SET_FROM_TYPED_ARRAY(T, N) \ case Scalar::N: \ if (!SetFromTypedArray<T>(cx, target, srcTypedArray, offset)) \ return false; \ break;JS_FOR_EACH_TYPED_ARRAY(SET_FROM_TYPED_ARRAY)#undef SET_FROM_TYPED_ARRAYdefault:MOZ_CRASH("Unsupported TypedArray type");}}else{// Remaining steps of 22.2.3.23.1.// Step 10.// We can't reorder this step because side-effects in step 16 can// detach the underlying array buffer from the typed array.uint32_ttargetLength=target->length();// Step 16.uint32_tsrcLength;if(!GetLengthProperty(cx,src,&srcLength))returnfalse;// Step 17 (Split into two checks to provide better error messages).if(targetOffset>targetLength){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_BAD_INDEX);returnfalse;}// Step 17 (Cont'd).uint32_toffset=uint32_t(targetOffset);if(srcLength>targetLength-offset){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_BAD_ARRAY_LENGTH);returnfalse;}// Steps 11-14, 18-21.if(srcLength>0){// GetLengthProperty in step 16 can lead to the execution of user// code which may detach the buffer. Handle this case here to// ensure SetFromNonTypedArray is never called with a detached// buffer. We still need to execute steps 21.a-b for their// possible side-effects.if(target->hasDetachedBuffer()){// Steps 21.a-b.RootedValuev(cx);if(!GetElement(cx,src,src,0,&v))returnfalse;doubleunused;if(!ToNumber(cx,v,&unused))returnfalse;// Step 21.c.JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_DETACHED);returnfalse;}switch(target->type()){#define SET_FROM_NON_TYPED_ARRAY(T, N) \ case Scalar::N: \ if (!SetFromNonTypedArray<T>(cx, target, src, srcLength, offset)) \ return false; \ break;JS_FOR_EACH_TYPED_ARRAY(SET_FROM_NON_TYPED_ARRAY)#undef SET_FROM_NON_TYPED_ARRAYdefault:MOZ_CRASH("Unsupported TypedArray type");}// Step 21.c.// SetFromNonTypedArray doesn't throw when the array buffer gets// detached.if(target->hasDetachedBuffer()){JS_ReportErrorNumberASCII(cx,GetErrorMessage,nullptr,JSMSG_TYPED_ARRAY_DETACHED);returnfalse;}}}// Step 29/22.args.rval().setUndefined();returntrue;}/* static */boolTypedArrayObject::set(JSContext*cx,unsignedargc,Value*vp){CallArgsargs=CallArgsFromVp(argc,vp);returnCallNonGenericMethod<TypedArrayObject::is,TypedArrayObject::set_impl>(cx,args);}/* static */constJSFunctionSpecTypedArrayObject::protoFunctions[]={JS_SELF_HOSTED_FN("subarray","TypedArraySubarray",2,0),#if 0 /* disabled until perf-testing is completed */ JS_SELF_HOSTED_FN("set", "TypedArraySet", 2, 0),#elseJS_FN("set",TypedArrayObject::set,1,0),#endifJS_SELF_HOSTED_FN("copyWithin","TypedArrayCopyWithin",3,0),JS_SELF_HOSTED_FN("every","TypedArrayEvery",1,0),JS_SELF_HOSTED_FN("fill","TypedArrayFill",3,0),JS_SELF_HOSTED_FN("filter","TypedArrayFilter",1,0),JS_SELF_HOSTED_FN("find","TypedArrayFind",1,0),JS_SELF_HOSTED_FN("findIndex","TypedArrayFindIndex",1,0),JS_SELF_HOSTED_FN("forEach","TypedArrayForEach",1,0),JS_SELF_HOSTED_FN("indexOf","TypedArrayIndexOf",2,0),JS_SELF_HOSTED_FN("join","TypedArrayJoin",1,0),JS_SELF_HOSTED_FN("lastIndexOf","TypedArrayLastIndexOf",1,0),JS_SELF_HOSTED_FN("map","TypedArrayMap",1,0),JS_SELF_HOSTED_FN("reduce","TypedArrayReduce",1,0),JS_SELF_HOSTED_FN("reduceRight","TypedArrayReduceRight",1,0),JS_SELF_HOSTED_FN("reverse","TypedArrayReverse",0,0),JS_SELF_HOSTED_FN("slice","TypedArraySlice",2,0),JS_SELF_HOSTED_FN("some","TypedArraySome",1,0),JS_SELF_HOSTED_FN("sort","TypedArraySort",1,0),JS_SELF_HOSTED_FN("entries","TypedArrayEntries",0,0),JS_SELF_HOSTED_FN("keys","TypedArrayKeys",0,0),JS_SELF_HOSTED_FN("values","TypedArrayValues",0,0),JS_SELF_HOSTED_SYM_FN(iterator,"TypedArrayValues",0,0),JS_SELF_HOSTED_FN("includes","TypedArrayIncludes",2,0),JS_SELF_HOSTED_FN("toString","ArrayToString",0,0),JS_SELF_HOSTED_FN("toLocaleString","TypedArrayToLocaleString",2,0),JS_FS_END};/* static */constJSFunctionSpecTypedArrayObject::staticFunctions[]={JS_SELF_HOSTED_FN("from","TypedArrayStaticFrom",3,0),JS_SELF_HOSTED_FN("of","TypedArrayStaticOf",0,0),JS_FS_END};/* static */constJSPropertySpecTypedArrayObject::staticProperties[]={JS_SELF_HOSTED_SYM_GET(species,"TypedArraySpecies",0),JS_PS_END};staticconstClassSpecTypedArrayObjectSharedTypedArrayPrototypeClassSpec={GenericCreateConstructor<TypedArrayConstructor,0,gc::AllocKind::FUNCTION>,GenericCreatePrototype,TypedArrayObject::staticFunctions,TypedArrayObject::staticProperties,TypedArrayObject::protoFunctions,TypedArrayObject::protoAccessors,nullptr,ClassSpec::DontDefineConstructor};/* static */constClassTypedArrayObject::sharedTypedArrayPrototypeClass={// Actually ({}).toString.call(%TypedArray%.prototype) should throw,// because %TypedArray%.prototype lacks the the typed array internal// slots. (It's not clear this is desirable -- particularly applied to// the actual typed array prototypes, see below -- but it's what ES6// draft 20140824 requires.) But this is about as much as we can do// until we implement @@toStringTag."???",JSCLASS_HAS_CACHED_PROTO(JSProto_TypedArray),JS_NULL_CLASS_OPS,&TypedArrayObjectSharedTypedArrayPrototypeClassSpec};// this default implementation is only valid for integer types// less than 32-bits in size.template<typenameNativeType>ValueTypedArrayObjectTemplate<NativeType>::getIndexValue(JSObject*tarray,uint32_tindex){static_assert(sizeof(NativeType)<4,"this method must only handle NativeType values that are ""always exact int32_t values");returnInt32Value(getIndex(tarray,index));}namespace{// and we need to specialize for 32-bit integers and floatstemplate<>ValueTypedArrayObjectTemplate<int32_t>::getIndexValue(JSObject*tarray,uint32_tindex){returnInt32Value(getIndex(tarray,index));}template<>ValueTypedArrayObjectTemplate<uint32_t>::getIndexValue(JSObject*tarray,uint32_tindex){uint32_tval=getIndex(tarray,index);returnNumberValue(val);}template<>ValueTypedArrayObjectTemplate<float>::getIndexValue(JSObject*tarray,uint32_tindex){floatval=getIndex(tarray,index);doubledval=val;/* * Doubles in typed arrays could be typed-punned arrays of integers. This * could allow user code to break the engine-wide invariant that only * canonical nans are stored into jsvals, which means user code could * confuse the engine into interpreting a double-typed jsval as an * object-typed jsval. * * This could be removed for platforms/compilers known to convert a 32-bit * non-canonical nan to a 64-bit canonical nan. */returnDoubleValue(CanonicalizeNaN(dval));}template<>ValueTypedArrayObjectTemplate<double>::getIndexValue(JSObject*tarray,uint32_tindex){doubleval=getIndex(tarray,index);/* * Doubles in typed arrays could be typed-punned arrays of integers. This * could allow user code to break the engine-wide invariant that only * canonical nans are stored into jsvals, which means user code could * confuse the engine into interpreting a double-typed jsval as an * object-typed jsval. */returnDoubleValue(CanonicalizeNaN(val));}}/* anonymous namespace */ValueTypedArrayObject::getElement(uint32_tindex){switch(type()){caseScalar::Int8:returnInt8Array::getIndexValue(this,index);caseScalar::Uint8:returnUint8Array::getIndexValue(this,index);caseScalar::Int16:returnInt16Array::getIndexValue(this,index);caseScalar::Uint16:returnUint16Array::getIndexValue(this,index);caseScalar::Int32:returnInt32Array::getIndexValue(this,index);caseScalar::Uint32:returnUint32Array::getIndexValue(this,index);caseScalar::Float32:returnFloat32Array::getIndexValue(this,index);caseScalar::Float64:returnFloat64Array::getIndexValue(this,index);caseScalar::Uint8Clamped:returnUint8ClampedArray::getIndexValue(this,index);caseScalar::Int64:caseScalar::Float32x4:caseScalar::Int8x16:caseScalar::Int16x8:caseScalar::Int32x4:caseScalar::MaxTypedArrayViewType:break;}MOZ_CRASH("Unknown TypedArray type");}voidTypedArrayObject::setElement(TypedArrayObject&obj,uint32_tindex,doubled){MOZ_ASSERT(index<obj.length());#ifdef JS_MORE_DETERMINISTIC// See the comment in ElementSpecific::doubleToNative.d=JS::CanonicalizeNaN(d);#endifswitch(obj.type()){caseScalar::Int8:Int8Array::setIndexValue(obj,index,d);return;caseScalar::Uint8:Uint8Array::setIndexValue(obj,index,d);return;caseScalar::Uint8Clamped:Uint8ClampedArray::setIndexValue(obj,index,d);return;caseScalar::Int16:Int16Array::setIndexValue(obj,index,d);return;caseScalar::Uint16:Uint16Array::setIndexValue(obj,index,d);return;caseScalar::Int32:Int32Array::setIndexValue(obj,index,d);return;caseScalar::Uint32:Uint32Array::setIndexValue(obj,index,d);return;caseScalar::Float32:Float32Array::setIndexValue(obj,index,d);return;caseScalar::Float64:Float64Array::setIndexValue(obj,index,d);return;caseScalar::Int64:caseScalar::Float32x4:caseScalar::Int8x16:caseScalar::Int16x8:caseScalar::Int32x4:caseScalar::MaxTypedArrayViewType:break;}MOZ_CRASH("Unknown TypedArray type");}/*** *** JS impl ***//* * TypedArrayObject boilerplate */#define IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Name,NativeType) \ JS_FRIEND_API(JSObject*) JS_New ## Name ## Array(JSContext* cx, uint32_t nelements) \ { \ return TypedArrayObjectTemplate<NativeType>::fromLength(cx, nelements); \ } \ JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayFromArray(JSContext* cx, HandleObject other) \ { \ return TypedArrayObjectTemplate<NativeType>::fromArray(cx, other); \ } \ JS_FRIEND_API(JSObject*) JS_New ## Name ## ArrayWithBuffer(JSContext* cx, \ HandleObject arrayBuffer, uint32_t byteOffset, int32_t length) \ { \ return TypedArrayObjectTemplate<NativeType>::fromBuffer(cx, arrayBuffer, byteOffset, \ length); \ } \ JS_FRIEND_API(bool) JS_Is ## Name ## Array(JSObject* obj) \ { \ if (!(obj = CheckedUnwrap(obj))) \ return false; \ const Class* clasp = obj->getClass(); \ return clasp == TypedArrayObjectTemplate<NativeType>::instanceClass(); \ } \ JS_FRIEND_API(JSObject*) js::Unwrap ## Name ## Array(JSObject* obj) \ { \ obj = CheckedUnwrap(obj); \ if (!obj) \ return nullptr; \ const Class* clasp = obj->getClass(); \ if (clasp == TypedArrayObjectTemplate<NativeType>::instanceClass()) \ return obj; \ return nullptr; \ } \ const js::Class* const js::detail::Name ## ArrayClassPtr = \ &js::TypedArrayObject::classes[TypedArrayObjectTemplate<NativeType>::ArrayTypeID()];IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int8,int8_t)IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8,uint8_t)IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint8Clamped,uint8_clamped)IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int16,int16_t)IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint16,uint16_t)IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Int32,int32_t)IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Uint32,uint32_t)IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float32,float)IMPL_TYPED_ARRAY_JSAPI_CONSTRUCTORS(Float64,double)#define IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Name, ExternalType, InternalType) \ JS_FRIEND_API(JSObject*) JS_GetObjectAs ## Name ## Array(JSObject* obj, \ uint32_t* length, \ bool* isShared, \ ExternalType** data) \ { \ if (!(obj = CheckedUnwrap(obj))) \ return nullptr; \ \ const Class* clasp = obj->getClass(); \ if (clasp != TypedArrayObjectTemplate<InternalType>::instanceClass()) \ return nullptr; \ \ TypedArrayObject* tarr = &obj->as<TypedArrayObject>(); \ *length = tarr->length(); \ *isShared = tarr->isSharedMemory(); \ *data = static_cast<ExternalType*>(tarr->viewDataEither().unwrap(/*safe - caller sees isShared flag*/)); \ \ return obj; \ }IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int8,int8_t,int8_t)IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint8,uint8_t,uint8_t)IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint8Clamped,uint8_t,uint8_clamped)IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int16,int16_t,int16_t)IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint16,uint16_t,uint16_t)IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Int32,int32_t,int32_t)IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint32,uint32_t,uint32_t)IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float32,float,float)IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64,double,double)staticconstClassOpsTypedArrayClassOps={nullptr,/* addProperty */nullptr,/* delProperty */nullptr,/* getProperty */nullptr,/* setProperty */nullptr,/* enumerate */nullptr,/* newEnumerate */nullptr,/* resolve */nullptr,/* mayResolve */TypedArrayObject::finalize,/* finalize */nullptr,/* call */nullptr,/* hasInstance */nullptr,/* construct */TypedArrayObject::trace,/* trace */};staticconstClassExtensionTypedArrayClassExtension={nullptr,TypedArrayObject::objectMoved,};#define IMPL_TYPED_ARRAY_PROPERTIES(_type) \{ \JS_INT32_PS("BYTES_PER_ELEMENT", _type##Array::BYTES_PER_ELEMENT, \ JSPROP_READONLY | JSPROP_PERMANENT), \JS_PS_END \}staticconstJSPropertySpecstatic_prototype_properties[Scalar::MaxTypedArrayViewType][2]={IMPL_TYPED_ARRAY_PROPERTIES(Int8),IMPL_TYPED_ARRAY_PROPERTIES(Uint8),IMPL_TYPED_ARRAY_PROPERTIES(Int16),IMPL_TYPED_ARRAY_PROPERTIES(Uint16),IMPL_TYPED_ARRAY_PROPERTIES(Int32),IMPL_TYPED_ARRAY_PROPERTIES(Uint32),IMPL_TYPED_ARRAY_PROPERTIES(Float32),IMPL_TYPED_ARRAY_PROPERTIES(Float64),IMPL_TYPED_ARRAY_PROPERTIES(Uint8Clamped)};#define IMPL_TYPED_ARRAY_CLASS_SPEC(_type) \{ \ _type##Array::createConstructor, \ _type##Array::createPrototype, \ nullptr, \ static_prototype_properties[Scalar::Type::_type], \ nullptr, \ static_prototype_properties[Scalar::Type::_type], \ nullptr, \ JSProto_TypedArray \}staticconstClassSpecTypedArrayObjectClassSpecs[Scalar::MaxTypedArrayViewType]={IMPL_TYPED_ARRAY_CLASS_SPEC(Int8),IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8),IMPL_TYPED_ARRAY_CLASS_SPEC(Int16),IMPL_TYPED_ARRAY_CLASS_SPEC(Uint16),IMPL_TYPED_ARRAY_CLASS_SPEC(Int32),IMPL_TYPED_ARRAY_CLASS_SPEC(Uint32),IMPL_TYPED_ARRAY_CLASS_SPEC(Float32),IMPL_TYPED_ARRAY_CLASS_SPEC(Float64),IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8Clamped)};#define IMPL_TYPED_ARRAY_CLASS(_type) \{ \ #_type "Array", \ JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) | \ JSCLASS_HAS_PRIVATE | \ JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array) | \ JSCLASS_DELAY_METADATA_BUILDER | \ JSCLASS_SKIP_NURSERY_FINALIZE | \ JSCLASS_BACKGROUND_FINALIZE, \ &TypedArrayClassOps, \ &TypedArrayObjectClassSpecs[Scalar::Type::_type], \ &TypedArrayClassExtension \}constClassTypedArrayObject::classes[Scalar::MaxTypedArrayViewType]={IMPL_TYPED_ARRAY_CLASS(Int8),IMPL_TYPED_ARRAY_CLASS(Uint8),IMPL_TYPED_ARRAY_CLASS(Int16),IMPL_TYPED_ARRAY_CLASS(Uint16),IMPL_TYPED_ARRAY_CLASS(Int32),IMPL_TYPED_ARRAY_CLASS(Uint32),IMPL_TYPED_ARRAY_CLASS(Float32),IMPL_TYPED_ARRAY_CLASS(Float64),IMPL_TYPED_ARRAY_CLASS(Uint8Clamped)};// The various typed array prototypes are supposed to 1) be normal objects,// 2) stringify to "[object <name of constructor>]", and 3) (Gecko-specific)// be xrayable. The first and second requirements mandate (in the absence of// @@toStringTag) a custom class. The third requirement mandates that each// prototype's class have the relevant typed array's cached JSProtoKey in them.// Thus we need one class with cached prototype per kind of typed array, with a// delegated ClassSpec.#define IMPL_TYPED_ARRAY_PROTO_CLASS(_type) \{ \/* * Actually ({}).toString.call(Uint8Array.prototype) should throw, because * Uint8Array.prototype lacks the the typed array internal slots. (Same as * with %TypedArray%.prototype.) It's not clear this is desirable (see * above), but it's what we've always done, so keep doing it till we * implement @@toStringTag or ES6 changes. */ \ #_type "ArrayPrototype", \ JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array), \ JS_NULL_CLASS_OPS, \ &TypedArrayObjectClassSpecs[Scalar::Type::_type] \}constClassTypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType]={IMPL_TYPED_ARRAY_PROTO_CLASS(Int8),IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8),IMPL_TYPED_ARRAY_PROTO_CLASS(Int16),IMPL_TYPED_ARRAY_PROTO_CLASS(Uint16),IMPL_TYPED_ARRAY_PROTO_CLASS(Int32),IMPL_TYPED_ARRAY_PROTO_CLASS(Uint32),IMPL_TYPED_ARRAY_PROTO_CLASS(Float32),IMPL_TYPED_ARRAY_PROTO_CLASS(Float64),IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Clamped)};/* static */boolTypedArrayObject::isOriginalLengthGetter(Nativenative){returnnative==TypedArray_lengthGetter;}booljs::IsTypedArrayConstructor(HandleValuev,uint32_ttype){switch(type){caseScalar::Int8:returnIsNativeFunction(v,Int8Array::class_constructor);caseScalar::Uint8:returnIsNativeFunction(v,Uint8Array::class_constructor);caseScalar::Int16:returnIsNativeFunction(v,Int16Array::class_constructor);caseScalar::Uint16:returnIsNativeFunction(v,Uint16Array::class_constructor);caseScalar::Int32:returnIsNativeFunction(v,Int32Array::class_constructor);caseScalar::Uint32:returnIsNativeFunction(v,Uint32Array::class_constructor);caseScalar::Float32:returnIsNativeFunction(v,Float32Array::class_constructor);caseScalar::Float64:returnIsNativeFunction(v,Float64Array::class_constructor);caseScalar::Uint8Clamped:returnIsNativeFunction(v,Uint8ClampedArray::class_constructor);caseScalar::MaxTypedArrayViewType:break;}MOZ_CRASH("unexpected typed array type");}template<typenameCharT>booljs::StringIsTypedArrayIndex(constCharT*s,size_tlength,uint64_t*indexp){constCharT*end=s+length;if(s==end)returnfalse;boolnegative=false;if(*s=='-'){negative=true;if(++s==end)returnfalse;}if(!JS7_ISDEC(*s))returnfalse;uint64_tindex=0;uint32_tdigit=JS7_UNDEC(*s++);/* Don't allow leading zeros. */if(digit==0&&s!=end)returnfalse;index=digit;for(;s<end;s++){if(!JS7_ISDEC(*s))returnfalse;digit=JS7_UNDEC(*s);/* Watch for overflows. */if((UINT64_MAX-digit)/10<index)index=UINT64_MAX;elseindex=10*index+digit;}if(negative)*indexp=UINT64_MAX;else*indexp=index;returntrue;}templatebooljs::StringIsTypedArrayIndex(constchar16_t*s,size_tlength,uint64_t*indexp);templatebooljs::StringIsTypedArrayIndex(constLatin1Char*s,size_tlength,uint64_t*indexp);/* ES6 draft rev 34 (2015 Feb 20) 9.4.5.3 [[DefineOwnProperty]] step 3.c. */booljs::DefineTypedArrayElement(JSContext*cx,HandleObjectobj,uint64_tindex,Handle<PropertyDescriptor>desc,ObjectOpResult&result){MOZ_ASSERT(obj->is<TypedArrayObject>());// These are all substeps of 3.b.// Steps i-iii are handled by the caller.// Steps iv-v.// We (wrongly) ignore out of range defines with a value.uint32_tlength=obj->as<TypedArrayObject>().length();if(index>=length)returnresult.succeed();// Step vi.if(desc.isAccessorDescriptor())returnresult.fail(JSMSG_CANT_REDEFINE_PROP);// Step vii.if(desc.hasConfigurable()&&desc.configurable())returnresult.fail(JSMSG_CANT_REDEFINE_PROP);// Step viii.if(desc.hasEnumerable()&&!desc.enumerable())returnresult.fail(JSMSG_CANT_REDEFINE_PROP);// Step ix.if(desc.hasWritable()&&!desc.writable())returnresult.fail(JSMSG_CANT_REDEFINE_PROP);// Step x.if(desc.hasValue()){// The following step numbers refer to 9.4.5.9// IntegerIndexedElementSet.// Steps 1-2 are enforced by the caller.// Step 3.doublenumValue;if(!ToNumber(cx,desc.value(),&numValue))returnfalse;// Steps 4-5, 8-9.if(obj->as<TypedArrayObject>().hasDetachedBuffer())returnresult.fail(JSMSG_TYPED_ARRAY_DETACHED);// Steps 10-16.TypedArrayObject::setElement(obj->as<TypedArrayObject>(),index,numValue);}// Step xii.returnresult.succeed();}/* JS Friend API */JS_FRIEND_API(bool)JS_IsTypedArrayObject(JSObject*obj){obj=CheckedUnwrap(obj);returnobj?obj->is<TypedArrayObject>():false;}JS_FRIEND_API(uint32_t)JS_GetTypedArrayLength(JSObject*obj){obj=CheckedUnwrap(obj);if(!obj)return0;returnobj->as<TypedArrayObject>().length();}JS_FRIEND_API(uint32_t)JS_GetTypedArrayByteOffset(JSObject*obj){obj=CheckedUnwrap(obj);if(!obj)return0;returnobj->as<TypedArrayObject>().byteOffset();}JS_FRIEND_API(uint32_t)JS_GetTypedArrayByteLength(JSObject*obj){obj=CheckedUnwrap(obj);if(!obj)return0;returnobj->as<TypedArrayObject>().byteLength();}JS_FRIEND_API(bool)JS_GetTypedArraySharedness(JSObject*obj){obj=CheckedUnwrap(obj);if(!obj)returnfalse;returnobj->as<TypedArrayObject>().isSharedMemory();}JS_FRIEND_API(js::Scalar::Type)JS_GetArrayBufferViewType(JSObject*obj){obj=CheckedUnwrap(obj);if(!obj)returnScalar::MaxTypedArrayViewType;if(obj->is<TypedArrayObject>())returnobj->as<TypedArrayObject>().type();if(obj->is<DataViewObject>())returnScalar::MaxTypedArrayViewType;MOZ_CRASH("invalid ArrayBufferView type");}JS_FRIEND_API(int8_t*)JS_GetInt8ArrayData(JSObject*obj,bool*isSharedMemory,constJS::AutoCheckCannotGC&){obj=CheckedUnwrap(obj);if(!obj)returnnullptr;TypedArrayObject*tarr=&obj->as<TypedArrayObject>();MOZ_ASSERT((int32_t)tarr->type()==Scalar::Int8);*isSharedMemory=tarr->isSharedMemory();returnstatic_cast<int8_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isShared*/));}JS_FRIEND_API(uint8_t*)JS_GetUint8ArrayData(JSObject*obj,bool*isSharedMemory,constJS::AutoCheckCannotGC&){obj=CheckedUnwrap(obj);if(!obj)returnnullptr;TypedArrayObject*tarr=&obj->as<TypedArrayObject>();MOZ_ASSERT((int32_t)tarr->type()==Scalar::Uint8);*isSharedMemory=tarr->isSharedMemory();returnstatic_cast<uint8_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));}JS_FRIEND_API(uint8_t*)JS_GetUint8ClampedArrayData(JSObject*obj,bool*isSharedMemory,constJS::AutoCheckCannotGC&){obj=CheckedUnwrap(obj);if(!obj)returnnullptr;TypedArrayObject*tarr=&obj->as<TypedArrayObject>();MOZ_ASSERT((int32_t)tarr->type()==Scalar::Uint8Clamped);*isSharedMemory=tarr->isSharedMemory();returnstatic_cast<uint8_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));}JS_FRIEND_API(int16_t*)JS_GetInt16ArrayData(JSObject*obj,bool*isSharedMemory,constJS::AutoCheckCannotGC&){obj=CheckedUnwrap(obj);if(!obj)returnnullptr;TypedArrayObject*tarr=&obj->as<TypedArrayObject>();MOZ_ASSERT((int32_t)tarr->type()==Scalar::Int16);*isSharedMemory=tarr->isSharedMemory();returnstatic_cast<int16_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));}JS_FRIEND_API(uint16_t*)JS_GetUint16ArrayData(JSObject*obj,bool*isSharedMemory,constJS::AutoCheckCannotGC&){obj=CheckedUnwrap(obj);if(!obj)returnnullptr;TypedArrayObject*tarr=&obj->as<TypedArrayObject>();MOZ_ASSERT((int32_t)tarr->type()==Scalar::Uint16);*isSharedMemory=tarr->isSharedMemory();returnstatic_cast<uint16_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));}JS_FRIEND_API(int32_t*)JS_GetInt32ArrayData(JSObject*obj,bool*isSharedMemory,constJS::AutoCheckCannotGC&){obj=CheckedUnwrap(obj);if(!obj)returnnullptr;TypedArrayObject*tarr=&obj->as<TypedArrayObject>();MOZ_ASSERT((int32_t)tarr->type()==Scalar::Int32);*isSharedMemory=tarr->isSharedMemory();returnstatic_cast<int32_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));}JS_FRIEND_API(uint32_t*)JS_GetUint32ArrayData(JSObject*obj,bool*isSharedMemory,constJS::AutoCheckCannotGC&){obj=CheckedUnwrap(obj);if(!obj)returnnullptr;TypedArrayObject*tarr=&obj->as<TypedArrayObject>();MOZ_ASSERT((int32_t)tarr->type()==Scalar::Uint32);*isSharedMemory=tarr->isSharedMemory();returnstatic_cast<uint32_t*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));}JS_FRIEND_API(float*)JS_GetFloat32ArrayData(JSObject*obj,bool*isSharedMemory,constJS::AutoCheckCannotGC&){obj=CheckedUnwrap(obj);if(!obj)returnnullptr;TypedArrayObject*tarr=&obj->as<TypedArrayObject>();MOZ_ASSERT((int32_t)tarr->type()==Scalar::Float32);*isSharedMemory=tarr->isSharedMemory();returnstatic_cast<float*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));}JS_FRIEND_API(double*)JS_GetFloat64ArrayData(JSObject*obj,bool*isSharedMemory,constJS::AutoCheckCannotGC&){obj=CheckedUnwrap(obj);if(!obj)returnnullptr;TypedArrayObject*tarr=&obj->as<TypedArrayObject>();MOZ_ASSERT((int32_t)tarr->type()==Scalar::Float64);*isSharedMemory=tarr->isSharedMemory();returnstatic_cast<double*>(tarr->viewDataEither().unwrap(/*safe - caller sees isSharedMemory*/));}